/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.amse.grigory.dchess.kernel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import org.amse.grigory.dchess.io.*;
import java.io.*;
import java.util.*;
import org.amse.grigory.dchess.rules.*;
import org.amse.grigory.dchess.view.DChessLabel;

/**
 *
 * @author grigory
 */
public final class Model implements IModel {
    // Fields

    private Desk myDesk;
    private ArrayList<IModelListener> myListener;
    private String myLastMove;
    private String myRulesFile;
    private int myWhiteTime,  myBlackTime;
    private Timer myTimer = null;
    private int myTime = 300;
    private int myWin = Rules.NOBODY_WIN;
    private volatile boolean myPaused = false;
    private ArrayList<Move> myLastMoveCoordinates;
    // Constructors

    public Model() {
        myListener = new ArrayList<IModelListener>();
        myLastMove = "";
        myDesk = new Desk(new BasicChessRules());
        myLastMoveCoordinates = new ArrayList<Move>();

    }

    public Model(String rulesFile) {
        this();
        myRulesFile = rulesFile;
    }

    // Getters
    public String getRulesFile() {
        return myRulesFile;
    }

    public String getLastMove() {
        if (myWin == Rules.BLACK_WIN) {
            return "Black won!";
        }
        if (myWin == Rules.WHITE_WIN) {
            return "White won!";
        }
        return myLastMove;
    }

    public int getHeight() {
        if (myDesk == null) {
            return 0;
        }
        return myDesk.getHeight();
    }

    public int getWidth() {
        if (myDesk == null) {
            return 0;
        }
        return myDesk.getWidth();
    }

    public String getName() {
        return myDesk.getName();
    }

    public int getIllegalSquareNumber() {
        return myDesk.getIllegalSquareNumber();
    }

    public int getIllegalX(int index) {
        return myDesk.getIllegalX(index);
    }

    public int getIllegalY(int index) {
        return myDesk.getIllegalY(index);
    }

    public String getFigureName(int x, int y) {
        return myDesk.getFigureName(x, y);
    }

    public int getFigureColor(int x, int y) {
        return myDesk.getFigureColor(x, y);
    }

    public int getColor() {
        return myDesk.getColor();
    }

    public int getWhiteTime() {
        return myWhiteTime;
    }

    public int getBlackTime() {
        return myBlackTime;
    }

    public Figure getWhiteFigure(int index) {
        return myDesk.getWhiteFigure(index);
    }

    public Figure getBlackFigure(int index) {
        return myDesk.getBlackFigure(index);
    }

    public int getWhiteCount() {
        return myDesk.getWhiteCount();
    }

    public int getBlackCount() {
        return myDesk.getWhiteCount();
    }
    // Setters

    public void setDesk(Desk desk) {
        myDesk = desk;
    }

    public void setRulesFile(String rulesFile) {
        myRulesFile = rulesFile;
    }

    public void setTime(int time) {
        myTime = time;
    }
    // Methods

    public void newGame() throws IOException, NullPointerException, Exception {
        myLastMove = "";
        myLastMoveCoordinates = null;
        IReader in = new XMLReader(myRulesFile);
        Rules rules;
        in.open();
        rules = in.createRules();
        if (rules == null) {
            System.out.println("Wrong rules!");
            return;
        }
        myDesk = new Desk(rules);
    }

    @Override
    public String toString() {
        return myDesk.toString();
    }

    public void addListener(IModelListener listener) {
        myListener.add(listener);
    }

    public void updateAll() {
        int length = myListener.size();
        for (int i = 0; i < length; ++i) {
            myListener.get(i).update();
        }
    }

    public void updateTime() {
        int length = myListener.size();
        for (int i = 0; i < length; ++i) {
            if (myListener.get(i) instanceof DChessLabel) {
                myListener.get(i).update();
            }
        }
    }

    public void start() {
        myDesk.start();
        //Timer
        myLastMoveCoordinates = new ArrayList<Move>();
        myPaused = false;
        myBlackTime = myTime;
        myWhiteTime = myTime;
        myWin = Rules.NOBODY_WIN;
        if (myTimer != null) {
            myTimer.stop();
        }
        myTimer = new Timer(1000, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (myDesk.getColor() == Rules.COLOR_BLACK) {
                    myBlackTime--;
                    updateTime();
                    if (myBlackTime == 0) {
                        myWin = Rules.WHITE_WIN;
                        updateAll();
                        myTimer.stop();
                    }
                } else {
                    myWhiteTime--;
                    updateTime();
                    if (myWhiteTime == 0) {
                        myWin = Rules.BLACK_WIN;
                        updateAll();
                        myTimer.stop();
                    }
                }
                if (myWin != Rules.NOBODY_WIN) {
                    myTimer.stop();
                }
            }
        });
        myTimer.start();        
        updateAll();
    }

    public boolean canMove(int x, int y, int tx, int ty) {
        return myDesk.canMove(x, y, tx, ty);
    }

    public boolean makeMove(int x, int y, int tx, int ty) {
        int count = myDesk.getMoveCount();
        if (myDesk.makeMove(x, y, tx, ty)) {
            myLastMove = myDesk.getMessage();
            if (count != myDesk.getMoveCount() + 1) {
                myLastMoveCoordinates.subList(myDesk.getCurrentMoveNumber(), myLastMoveCoordinates.size()).clear();
            }
            myLastMoveCoordinates.add(new Move(x, y, tx, ty));
            updateAll();
            return true;
        }
        return false;
    }

    public int isWin() {
        if (myWin != Rules.NOBODY_WIN) {
            return myWin;
        }
        myWin = myDesk.isWin();
        return myWin;
    }

    public Desk getDeskClone() {
        return myDesk.clone();
    }

    public boolean isPaused() {
        return myPaused;
    }

    public void pause() {
        myPaused = true;
        if (myTimer != null) {
            myTimer.stop();
        }
        updateAll();
    }

    public void continueGame() {
        myPaused = false;
        if (myTimer != null) {
            myTimer.start();
        }
        myLastMove = myDesk.getMessage();myLastMove = myDesk.getMessage();
        updateAll();
    }

    public Move getMoveCoordinates(int index) {
        if (index < 0) {
            return null;
        }
        if (index >= myLastMoveCoordinates.size()) {
            return null;
        }
        return myLastMoveCoordinates.get(index);
    }

    public int getMovesCount() {
        return myLastMoveCoordinates.size();
    }

    public void undo() {
        if (myDesk.undo()) {
            updateAll();
        }
    }

    public boolean canUndo() {
        return myDesk.canUndo();
    }

    public void redo() {
        if (myDesk.redo()) {
            updateAll();
        }
    }

    public boolean canRedo() {
        return myDesk.canRedo();
    }

    public int getCurrentMoveNumber(){
        return myDesk.getCurrentMoveNumber();
    }

    public void setBlackTime(int time){
        myBlackTime=time;
    }
    public void setWhiteTime(int time){
        myWhiteTime=time;
    }

}
